#include "BoostControl.h"
#include <iostream>



BoostControl::BoostControl()
{
    memset( _readBuffer, 0, sizeof(_readBuffer));
    preConnectDevice();
//    int fd = open("/dev/ttyUSB0",O_RDWR  | O_NONBLOCK );
//    if(-1 == fd){
//        cout << "ioctrl false!" << endl;
//    }else {
//        //::tcflush(fd,TCOFLUSH);
//    }
//    //close(fd);

}

inline void undo(){

}



void BoostControl::InitDevice()
{

}

QStringList BoostControl::ScanSerial()
{

}

std::string BoostControl::SendUntilRec(const char *sendBuf, int msecs)
{
    try{
        boost::asio::write(*_serialPort_ptr, buffer(sendBuf,sizeof(sendBuf)));
        _bReply = false ;
        waitReply() ;
    }
    catch(const boost::exception &e)
    {
        //DUMPERROR(e) ;
        qWarning("Send Buff Error!");
        _condReply.notify_all();
    }


    return currentBuff;
}

bool BoostControl::GetOpened()
{
    return pInfo.isOpen;
    //return _serialPort_ptr->is_open();
}


void BoostControl::CloseSerial()
{
    std::lock_guard<std::recursive_mutex> lck(_mtx) ;

    pInfo.isOpen = false;

    if (0 == ::tcflush(_serialPort_ptr->lowest_layer().native_handle(),TCIOFLUSH)){
        boost::system::system_error d = boost::system::error_code();
        cout <<"\t "<< " clear serial buff :"<<d.what()<<endl;
    }

    if ( _serialPort_ptr ) {
        if ( _serialPort_ptr->is_open() ) {
            try{
                _service.stop() ;
                _serialPort_ptr->close();
                _thService.join() ;
            }catch ( const boost::system::system_error &e ) {
                std::cout<<":" <<"system:"<< e.what() << std::endl ;
            }
        }


        _serialPort_ptr = nullptr;
    }
    memset( _readBuffer, 0, sizeof(_readBuffer));
}

void BoostControl::SendBuff(const  char *sendBuf)
{
    try{
        boost::asio::write(*_serialPort_ptr, buffer(sendBuf,sizeof(sendBuf)));
    }
    catch(const boost::exception &e)
    {
        //DUMPERROR(e) ;
        qWarning("Send Buff Error!");
    }
}

void BoostControl::OpenPort(const char* port, int bau)
{
    std::lock_guard<std::recursive_mutex> lck(_mtx) ;
    pInfo.name = port;
    pInfo.port = bau;

    try {
            //_serialPort_ptr.reset( new  serial_port(_service, pInfo.name.data()));
            _serialPort_ptr->open( pInfo.name.data());
            _serialPort_ptr->set_option(serial_port::baud_rate(pInfo.port));
            _serialPort_ptr->set_option(serial_port::flow_control(serial_port::flow_control::none)) ;
            _serialPort_ptr->set_option(serial_port::parity(serial_port::parity::none)) ;
            _serialPort_ptr->set_option(serial_port::stop_bits(serial_port::stop_bits::one)) ;
            _serialPort_ptr->set_option(serial_port::character_size(serial_port::character_size(8))) ;

#if USE_ASYNC
//            boost::asio::async_read( *_serialPort_ptr, boost::asio::buffer(_readBuffer),
//                                     boost::bind( &BoostControl::recvReply, this, _1, _2 ) ) ;

            boost::asio::async_read( *_serialPort_ptr, boost::asio::buffer(recvData),
                                     boost::bind( &BoostControl::recvReplyInterrupt, this, _1, _2 ) ) ;
#endif
            _thService = std::thread([this]() {_service.run();}) ;
            pInfo.isOpen = true;

    }
    catch ( const boost::system::system_error &e ) {
        std::cout<<port<<":" <<"system:"<< e.what() << std::endl ;
    }
    catch ( const boost::exception &e ) {
        std::cout <<"exception:"<< std::endl ;
        //DUMPERROR(e) ;
    }
}

/// 主动读取数据，不推荐，接收方最好使用异步方式
bool BoostControl::ReadBuff()
{
    if(USE_ASYNC) return false;
    std::lock_guard<std::recursive_mutex> lck(_mtx) ;
    boost::asio::streambuf _info;

    boost::asio::read(*_serialPort_ptr, _info.prepare(21), transfer_exactly(25) );
    _info.commit(21);
    std::string request_data(boost::asio::buffers_begin(_info.data()), boost::asio::buffers_end(_info.data()));
    request_data.erase(0,request_data.size() - 21);
    _sigUpdate(request_data);
    return true;
}

void BoostControl::preConnectDevice()
{
    try {
        if ( !_serialPort_ptr ) {
            _serialPort_ptr.reset( new  serial_port(_service));
        }else{
            qWarning("注意，串口资源上次未释放!");
        }
    }
    catch ( const boost::system::system_error &e ) {
        std::cout <<"Serial Pre Failed!\n" <<"system:"<< e.what() << std::endl ;
    }
    catch ( const boost::exception &e ) {
        std::cout <<"exception:" << std::endl ;
        //DUMPERROR(e) ;
    }
}


void BoostControl::recvReply( const boost::system::error_code &ec, size_t )
{
    if ( !ec ) {
        std::lock_guard<std::recursive_mutex> lck(_mtx) ;
        _bReply = true ;

        if(_readBuffer[0] != (UC)0xff){
            memset( _readBuffer, 0, sizeof(_readBuffer));
        }else {
            currentBuff.clear();

            _condReply.notify_one() ;

            for(int i =0;i<sizeof(_readBuffer);i++){
                currentBuff.push_back(UC(_readBuffer[i]));
            }
            _sigUpdate(currentBuff);
        }

        if(pInfo.isOpen)
            boost::asio::async_read( *_serialPort_ptr, boost::asio::buffer(_readBuffer),
                                 boost::bind( &BoostControl::recvReply, this, _1, _2 ) ) ;

    }else {
        cout << ec.message()<<endl;
    }


}

void BoostControl::recvReplyInterrupt(const boost::system::error_code &ec, size_t)
{
    if ( !ec ) {
        std::lock_guard<std::recursive_mutex> lck(_mtx) ;

        if(cir_buff.buff.size() == 21){
            if(cir_buff.getHeader()){
                bool crc = cir_buff.CRC();
                if(crc){
                    while(!cir_buff.buff.empty()){
                        cir_buff.buff.pop();
                    }

                    _sigUpdate(cir_buff.okData);
                    cir_buff << recvData[0];
                }else{
                    cir_buff < recvData[0];
                }
            }else {
                 cir_buff < recvData[0];
            }
        }else {
            cir_buff << recvData[0];
        }

        boost::asio::async_read( *_serialPort_ptr, boost::asio::buffer(recvData),
                                 boost::bind( &BoostControl::recvReplyInterrupt, this, _1, _2 ) ) ;

    }else {
        cout << ec.message()<<endl;
    }
}

void BoostControl::waitReply()
{
    using namespace std::chrono ;
    Millsecond m1 = steady_clock::now() ;
    std::unique_lock<std::mutex> lck(_mtxReply) ;
    // 考虑到异常情况，设置超时时间
    _condReply.wait_for( lck, std::chrono::milliseconds(100), [this]{return _bReply ;}) ;
    Millsecond m2 = steady_clock::now() ;
    //std::cout << (m2 - m1).count() << std::endl ;
    std::this_thread::sleep_for( std::chrono::milliseconds(50) ) ;
}
